package edu.predatorwars.server.store;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import edu.predatorwars.shared.models.Board;
import edu.predatorwars.shared.models.Buff;
import edu.predatorwars.shared.models.Creature;
import edu.predatorwars.shared.models.Location;
import edu.predatorwars.shared.models.Resource;
import edu.predatorwars.shared.models.Terrain;

//model classes must implement serializable
public class DataStore implements DataStoreInterface {

	public DataStore(){
		if(getCreatures().length == 0)
			storeDefaultCreatures();
		if(getResources().length == 0)
			storeDefaultResources();
		if(getBoards().length == 0)
			storeDefaultBoards();
	}

	//returns all boards
	@Override
	public Board[] getBoards() {
		File currentDirectory = new File(".");    

		String[] fileNames = currentDirectory.list();

		ArrayList<Board> boards = new ArrayList<Board>();

		for(String name : fileNames){
			if(name.contains(".board")){
				try{
					FileInputStream fis = new FileInputStream(name); 
					ObjectInputStream ois = new ObjectInputStream(fis); 
					Board board = (Board) ois.readObject(); 
					ois.close();
					boards.add(board);
				}catch(Exception e){
					System.out.println("Couldn't get a board.");
					e.printStackTrace();
				}
			}
		}

		return (Board[]) boards.toArray(new Board[]{});
	}

	//stores board to disk
	@Override
	public boolean storeBoard(Board b) {
		try {

			String fname = b.getName() + ".board";

			File test = new File(fname);
			if(test.exists()){
				test.delete();
			}

			FileOutputStream fos = new FileOutputStream(fname); 
			ObjectOutputStream oos = new ObjectOutputStream(fos); 
			oos.writeObject(b);
			oos.flush(); 
			oos.close(); 
			fos.close();

			return true;
		} catch (IOException e) {
			System.out.println("SORRY, couldn't save the board!");
			e.printStackTrace();
			return false;
		} 
	}

	//returns all creatures
	@Override
	public Creature[] getCreatures() {
		File currentDirectory = new File(".");    

		String[] fileNames = currentDirectory.list();

		ArrayList<Creature> creatures = new ArrayList<Creature>();

		for(String name : fileNames){
			if(name.contains(".creature")){
				try{
					FileInputStream fis = new FileInputStream(name); 
					ObjectInputStream ois = new ObjectInputStream(fis); 
					Object rtnObj = ois.readObject();

					if(rtnObj instanceof Creature)
						creatures.add((Creature)rtnObj);
					ois.close();
				}catch(Exception e){
					e.printStackTrace();
					System.out.println("Couldn't get a Creature.");
				}
			}
		}

		return (Creature[]) creatures.toArray(new Creature[]{});
	}

	//saves creature
	@Override
	public boolean storeCreature(Creature c) {
		try {

			String fname = "c" + c.getCreatureType() + ".creature";

			File test = new File(fname);
			if(test.exists()){
				test.delete();
			}

			FileOutputStream fos = new FileOutputStream(fname); 
			ObjectOutputStream oos = new ObjectOutputStream(fos); 
			oos.writeObject(c);
			oos.flush(); 
			oos.close(); 
			fos.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("SORRY, couldn't save the creature!");
			return false;
		} 
	}

	//returns all resources
	@Override
	public Resource[] getResources() {
		File currentDirectory = new File(".");    

		String[] fileNames = currentDirectory.list();

		ArrayList<Resource> resources = new ArrayList<Resource>();

		for(String name : fileNames){
			if(name.contains(".resource")){
				try{
					FileInputStream fis = new FileInputStream(name); 
					ObjectInputStream ois = new ObjectInputStream(fis); 
					Resource resource = (Resource) ois.readObject(); 
					ois.close();
					resources.add(resource);
				}catch(Exception e){
					System.out.println("Couldn't get a resource.");
					e.printStackTrace();
				}
			}
		}

		return (Resource[]) resources.toArray(new Resource[]{});
	}

	//stores resource
	@Override
	public boolean storeResource(Resource r) {
		try {

			String fname = "r" + r.getResourceType() + ".resource";

			File test = new File(fname);
			if(test.exists()){
				test.delete();
			}

			FileOutputStream fos = new FileOutputStream(fname); 
			ObjectOutputStream oos = new ObjectOutputStream(fos); 
			oos.writeObject(r);
			oos.flush(); 
			oos.close(); 
			fos.close();

			return true;
		} catch (IOException e) {
			System.out.println("SORRY, couldn't save the resource!");
			e.printStackTrace();
			return false;
		} 
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if(test()){
			System.out.println("Everything's workin' great!");
		}else{
			System.out.println("WE'VE GOT PROBLEMS!!!!!!!!!");
		}

	}

	public static boolean test(){
		boolean toReturn = true;

		//testing board persistence

		/*
		DataStore testDS = new DataStore();
		Board testBoard = new Board();
		testDS.saveBoard(testBoard);
		Board[] testBoards = testDS.getBoards();
		for(Board b : testBoards){
			if(b.equals(testBoard)){
				toReturn = true;
			}
		}

		 */

		//		DataStoreResource testDS = new DataStoreResource();
		//		Board testBoard = new Board();
		//		testDS.saveBoard(testBoard);
		//		Board returned = testDS.getBoard(testBoard.getName());
		//		if(!testBoard.equals(returned)){
		//			toReturn = false;
		//		}

		//TODO - still need to test other methods


		return toReturn;
	}

	//returns particular board based on name
	@Override
	public Board getBoard(String boardName) {
		String fname = boardName + ".board";

		File test = new File(fname);
		if(!test.exists()){
			System.out.println(fname + " board doesn't seem to exist!");
			return null;
		}

		try { 
			Board toReturn;
			FileInputStream fis = new FileInputStream(fname); 
			ObjectInputStream ois = new ObjectInputStream(fis); 
			toReturn = (Board) ois.readObject(); 
			ois.close(); 

			return toReturn;

		} catch(Exception e) { 
			System.out.println("SORRY, couldn't get " + fname + "!"); 
			return null;
		} 
	}

	//returns particular creature based on name
	@Override
	public Creature getCreature(String creatureName) {
		String fname = creatureName + ".creature";

		File test = new File(fname);
		if(!test.exists()){
			System.out.println(fname + " creature doesn't seem to exist!");
			return null;
		}

		try { 
			Creature toReturn;
			FileInputStream fis = new FileInputStream(fname); 
			ObjectInputStream ois = new ObjectInputStream(fis); 
			toReturn = (Creature) ois.readObject(); 
			ois.close(); 

			return toReturn;

		} catch(Exception e) { 
			System.out.println("SORRY, couldn't get " + fname + "!"); 
			return null;
		} 
	}

	//returns particular resource based on name
	@Override
	public Resource getResource(String resourceName) {
		String fname = resourceName + ".resource";

		File test = new File(fname);
		if(!test.exists()){
			System.out.println(fname + " resource doesn't seem to exist!");
			return null;
		}

		try { 
			Resource toReturn;
			FileInputStream fis = new FileInputStream(fname); 
			ObjectInputStream ois = new ObjectInputStream(fis); 
			toReturn = (Resource) ois.readObject(); 
			ois.close(); 

			return toReturn;

		} catch(Exception e) { 
			System.out.println("SORRY, couldn't get " + fname + "!"); 
			return null;
		} 
	}

	public void storeDefaultBoards()
	{
		Terrain terrain;
		Location[][] locations = new Location[20][20];
		for(int x = 0;x<locations.length;x++)
			for(int y = 0;y< locations[x].length;y++)
			{
				if(x == 4 && y == 4)
					terrain = new Terrain(Terrain.MOUNTAIN,false,true);
				else if(x == 0 && y != 0 && y!=8)
					terrain = new Terrain(Terrain.WATER,false,false);
				else
					terrain = new Terrain(Terrain.GRASS,true,false);
				locations[x][y] = new Location(terrain, (x == 0 && y == 0) || (x == 19 && y == 19) || (x==1 && y ==19));
			}

		storeBoard( new Board("The Great Safari", locations,5));


		locations = new Location[10][10];
		for(int x = 0;x<locations.length;x++)
			for(int y = 0;y< locations[x].length;y++)
			{
				if(x == 4 && y == 4)
					terrain = new Terrain(Terrain.MOUNTAIN,false,true);
				else if(x == 0 && y != 0 && y!=8)
					terrain = new Terrain(Terrain.WATER,false,false);
				else
					terrain = new Terrain(Terrain.GRASS,true,false);
				locations[x][y] = new Location(terrain, (x == 0 && y == 0) || (x == 9 && y == 9) || (x==1 && y ==9));
			}

		storeBoard( new Board("The Mini Safari", locations,3));
	}

	public void storeDefaultResources()
	{
		Resource resource;
		Buff[] buffs;

		buffs = new Buff[] {new Buff(Creature.STAT_STRENGTH,4f,4)};
		resource = new Resource(Resource.RAM, "Feast on the Ram meat to boost your strength for a limited time.",buffs);
		storeResource(resource);

		buffs = new Buff[] {new Buff(Creature.STAT_SIGHT,4f,4)};
		resource = new Resource(Resource.HAWK, "Feast on the Hawk meat to boost your Sight for a limited time.",buffs);
		storeResource(resource);

		buffs = new Buff[] {new Buff(Creature.STAT_SPEED,4f,4)};
		resource = new Resource(Resource.RABBIT, "Feast on the Rabbit meat to boost your Speed for a limited time.",buffs);
		storeResource(resource);

		buffs = new Buff[] {new Buff(Creature.STAT_ARMOR,4f,4)};
		resource = new Resource(Resource.TURTLE, "Feast on the Turtle meat to boost your Armor for a limited time.",buffs);
		storeResource(resource);

		buffs = new Buff[] {new Buff(Creature.STAT_HEALTH,2f,5)};
		resource = new Resource(Resource.WATER, "Drink from the fresh water pool to regain your vitality.",buffs);
		storeResource(resource);
	}


	public void storeDefaultCreatures()
	{
		Creature creature;
		Map<Integer,Float> stats;

		stats = new HashMap<Integer,Float>();
		stats.put(Creature.STAT_ARMOR, 3f);
		stats.put(Creature.STAT_HEALTH, 20f);
		stats.put(Creature.STAT_MAX_HEALTH, 20f);
		stats.put(Creature.STAT_SIGHT, 3f);
		stats.put(Creature.STAT_SPEED, 3f);
		stats.put(Creature.STAT_STRENGTH, 5f);
		creature = new Creature(Creature.TYPE_BEAR,stats);
		storeCreature(creature);

		stats = new HashMap<Integer,Float>();
		stats.put(Creature.STAT_ARMOR, 4f);
		stats.put(Creature.STAT_HEALTH, 25f);
		stats.put(Creature.STAT_MAX_HEALTH, 25f);
		stats.put(Creature.STAT_SIGHT, 4f);
		stats.put(Creature.STAT_SPEED, 2f);
		stats.put(Creature.STAT_STRENGTH, 3f);
		creature = new Creature(Creature.TYPE_ELEPHANT, stats);
		storeCreature(creature);

		stats = new HashMap<Integer,Float>();
		stats.put(Creature.STAT_ARMOR, 2f);
		stats.put(Creature.STAT_HEALTH, 18f);
		stats.put(Creature.STAT_MAX_HEALTH, 18f);
		stats.put(Creature.STAT_SIGHT, 4f);
		stats.put(Creature.STAT_SPEED, 4f);
		stats.put(Creature.STAT_STRENGTH, 4f);
		creature = new Creature(Creature.TYPE_GORILLA,stats);
		storeCreature(creature);

		stats = new HashMap<Integer,Float>();
		stats.put(Creature.STAT_ARMOR, 1f);
		stats.put(Creature.STAT_HEALTH, 15f);
		stats.put(Creature.STAT_MAX_HEALTH, 15f);
		stats.put(Creature.STAT_SIGHT, 4f);
		stats.put(Creature.STAT_SPEED, 5f);
		stats.put(Creature.STAT_STRENGTH, 2f);
		creature = new Creature(Creature.TYPE_SNAKE, stats);
		storeCreature(creature);

		stats = new HashMap<Integer,Float>();
		stats.put(Creature.STAT_ARMOR, 2f);
		stats.put(Creature.STAT_HEALTH, 18f);
		stats.put(Creature.STAT_MAX_HEALTH, 18f);
		stats.put(Creature.STAT_SIGHT, 4f);
		stats.put(Creature.STAT_SPEED, 5f);
		stats.put(Creature.STAT_STRENGTH, 3f);
		creature = new Creature(Creature.TYPE_WOLF,stats);
		storeCreature(creature);
	}
}
